#include "StdAfx.h"
#include "HXTTSEngine.h"

HXTTSEngine::HXTTSEngine(void)
: m_rampFunc(HXBM_SIN)
{
	m_fps = 400;
	m_visemeModulator = 0.6;
	m_rate = -3.0;
	m_overlap = 0.5;
	m_enginekHz = 22;
}

/*
HXTTSEngine::HXTTSEngine(int fps, double visemeModulator, double rate, double overlap, HXBlendMode rampFunc)
{
	m_visemeModulator = visemeModulator; 
	m_fps = fps;
	m_rate = rate;
	m_overlap = overlap;
	m_rampFunc = rampFunc;
}
*/

HXTTSEngine::~HXTTSEngine(void)
{
}

void HXTTSEngine::ToHXViseme(string& phone, double endpoint, double previous, vector<vector<HXViseme>>& visemeSequence)
{

	map<wstring,vector<vector<HXVisemeBlendShape>>>::iterator mit = m_visemeMap.find(StringToWString(phone));

	if (mit != m_visemeMap.end())
	{

		unsigned int choice = 0;
		if (mit->second.size() > 1)
		{
			rand_s(&choice);
			choice %= mit->second.size();
		}

		vector<HXVisemeBlendShape>::iterator vit;

		double totalDuration = endpoint-previous;
		for (vit=mit->second[choice].begin(); vit < mit->second[choice].end(); vit++ )
		{   

			// offset and duration are relative values on the acutal duration of total viseme
			double visemeDuration = totalDuration*vit->duration; // length within total viseme
			//double visemeEndPoint = (endpoint - totalDuration*(1-vit->m_offset)) + visemeDuration; // relative position within the total viseme
			//double visemeEndPoint = (vit->m_offset + vit->m_duration)*endpoint + (1 - vit->m_offset - vit->m_duration)*previous; // relative position within the total viseme
			//double visemeEndPoint = (vit->m_offset + vit->m_duration)*(endpoint-previous) + previous;
			double visemeEndPoint = previous + vit->offset*totalDuration + visemeDuration; // relative position within the total viseme

  			AddToVisemeSequence(HXViseme(vit->name,visemeEndPoint,visemeDuration,vit->amplitude,vit->rampFunc),visemeSequence);


		}
	}
	
} 

int HXTTSEngine::AddToVisemeSequence(const HXViseme& vin, vector<vector<HXViseme>>& output)
{

	//cout << "Adding " << vin.label;

	// find the start and end frames (overlapping half(default) its size with neighbours)
	//double overlap = 0.5;
	int startFrame = static_cast<int>(m_fps * (vin.endpoint - vin.duration*(1+m_overlap)));
	int endFrame = static_cast<int>(m_fps * (vin.endpoint + vin.duration*m_overlap));
	//unsigned int startFrame = static_cast<unsigned int>(m_fps * (vin.endpoint - vin.duration));
	//unsigned int endFrame = static_cast<unsigned int>(m_fps * (vin.endpoint + vin.duration));
	//int midFrame = (endFrame + startFrame) / 2;
	//unsigned int peakFrame = static_cast<unsigned int>(m_fps * (vin.endpoint - vin.duration));
	//int peakFrame = midFrame;

	if (endFrame - startFrame < 2)
	{
		endFrame++;
		startFrame--;
	}

	// check boundaries
	if (startFrame < 0)
	{
		startFrame = 0;
	}

	if (static_cast<int>(output.size()) < endFrame+1)
	{
		// resize to fit in data
		output.resize(endFrame+1);
	}


	//cout << " " << startFrame << " to " << endFrame << endl;

	if (vin.label.size())
	{
		for (int f = startFrame; f < endFrame; f++)
		{
			double ramp = CalcRamp(f, startFrame, endFrame, vin.rampFunc);
			ramp *= vin.amplitude*m_visemeModulator;
			AddToFrame(HXViseme(vin.label, vin.endpoint, vin.duration, ramp, vin.rampFunc), output[f]);
		}
	}

	return 0;
}

double HXTTSEngine::CalcRamp(double cframe, double sframe, double eframe, HXBlendMode rampFunc)
{
	double diff = (cframe - sframe) / (eframe - sframe);
	switch ((rampFunc & HXBM_DEFAULT) ? m_rampFunc : rampFunc)
	{
	case HXBM_LINEAR:	
		return (diff > 0.5) ? (1-diff)*2 : diff*2;
	case HXBM_HSIN:
		return TransformHalfSin(diff*2);
	case HXBM_SIN:
		return TransformSin(diff*2);
	case HXBM_SINC:
		return TransformSinc(diff*2);
	case HXBM_MAX:
	default:
		return 1.0;
	}
}

int HXTTSEngine::AddToFrame(const HXViseme& vin, vector<HXViseme>& output)
{

	//output.push_back(vin);
	
	if (output.empty())
	{
		output.push_back(vin);
	}
	else
	{
		// need to search to see if identical viseme is contained in frame
		vector<HXViseme>::iterator visemeIter;

		// search the corresponding viseme group
		bool added = false;
		for(visemeIter = output.begin(); visemeIter != output.end(); ++visemeIter) 
		{
			if (visemeIter->label == vin.label)
			{
				// take the maximum of the two
				visemeIter->amplitude = (visemeIter->amplitude > vin.amplitude) ? visemeIter->amplitude : vin.amplitude; // max
				//visemeIter->amplitude = (visemeIter->amplitude > vin.amplitude) ? vin.amplitude : visemeIter->amplitude; // min
				//visemeIter->amplitude = (visemeIter->amplitude + vin.amplitude) / 2.0; // avg
				added = true;
				break;
			}
		}
		if (!added)
		{
			output.push_back(vin);
		}

	}
	
	

	return 0;
}